# ==================6.集合==================
"""
python 中 set 与 dict 类似，也是一组 key 的集合，但不存储 value 。
由于 key 不能重复，所以，在 set 中，没有重复的 key 。
"""
num = {}
print(type(num))  # <class 'dict'>
num = {1, 2, 3, 4}
print(type(num))  # <class 'set'>
# @.集合的创建
"""
1. 先创建对象再加入元素。
2. 在创建空集合的时候只能使用 s = set() ，因为 s = {} 创建的是空字典。
3. 直接把一堆元素用花括号括起来 {元素1, 元素2, ..., 元素n} 。
4. 重复元素在 set 中会被自动被过滤。
"""
set_0 = {12, 3243, 434}
print(set_0)

set_1 = set()
set_1.add('12')
set_1.add(12)
set_1.add('banana')

print(set_1)  # {'12', 12, 'banana'}

# 使用set(value)工厂函数，把列表或元组转换成集合。
set_str = set("abcdefj")
print(set_str)  # {'b', 'd', 'a', 'f', 'c', 'e', 'j'}

set_tuple = set(('google', 'apple', 'xiaomi', 'huawei'))
print(set_tuple)  # {'huawei', 'google', 'xiaomi', 'apple'}

set_list = set(['1', '2', 3, '4', '3'])
print(set_list)  # {3, '2', '3', '4', '1'}

"""
从结果发现集合的两个特点：无序 (unordered) 和唯一 (unique)。
由于 set 存储的是无序集合，所以我们不可以为集合创建索引或执行切片(slice)操作，也没有键(keys)可用来获取集合中
元素的值，但是可以判断一个元素是否在集合中。
"""
lst = [0, 12, 3, 4, 5, 546, 7, 7, 8, 12, 3]

temp = []
for item in lst:
    if item not in temp:
        temp.append(item)
print(temp)  # [0, 12, 3, 4, 5, 546, 7, 8]

set_lst = set(lst)
print(list(set_lst))  # [0, 546, 3, 4, 5, 7, 8, 12]

# @.访问集合中的值
lst = [0, 12, 3, 4, 5, 546, 7, 7, 8, 12, 3]
set_lst = {3, '4', '3', '2', '1', 3}
# 1. 可以使用 len() 內建函数得到集合的大小。
print(len(set_lst))  # 5

# 2. 可以使用 for 把集合中的数据一个个读取出来
for item in set_lst:
    print(item)

# @.集合的内置方法
set_lst = {'apple', 'xiaomi', 'huawei'}

# 1. set.add('hubary') 用于给集合添加元素，如果添加的元素在集合中已存在，则不执行任何操作。
set_lst.add('hubary')
print(set_lst)

#  2. set.update(set) 用于修改当前集合，可以添加新的元素或集合到当前集合中，如果添加的元素在集合中已存在，
# 则该元素只会出现一次，重复的会忽略。
x = {"1", "2", "3"}
y = {"3", "4", "5"}
x.update(y)
print(x)
# 3. 删除不存在报错 set.remove(item) 用于移除集合中的指定元素。如果元素不存在，则会发生错误
x.remove('3')
print(x)
# x.remove('hubary')  # KeyError: 'hubary'

# 4. 删除不存在不报错 set.discard(value) 用于移除指定的集合元素。 remove() 方法在移除一个不存在的元素时会发生错误，而discard() 方法不会。
x.discard('5')
x.discard('hubary')  # 不存在不报错
print(x)

# 5. set.pop() 用于随机移除一个元素。
x.pop()
print(x)

"""
6. 交集  
intersection 十字路口;交叉路口;交点;横断;交叉;相交
由于 set 是无序和无重复元素的集合，所以两个或多个 set 可以做数学意义上的集合操作。
1. set.intersection(set1, set2 ...) 返回两个集合的交集。
2. set1 & set2 返回两个集合的交集。
3. set.intersection_update(set1, set2 ...) 交集，在原始的集合上移除不重叠的元素。
"""
set_6 = set('ab1cd')
set_7 = set('12ba')
print(set_6.intersection(set_7))
print(set_6)  # 原集合不变

print(set_6 & set_7)  # 交集
set_6.intersection_update(set_7)
print(set_6)  # 原集合改变

"""
7.并集
set.union(set1, set2...) 返回两个集合的并集。
set1 | set2 返回两个集合的并集。
"""

set_70 = set('ab1cd')
set_71 = set('12ba')
print(set.union(set_71, set_70))  # {'a', 'c', 'b', '2', 'd', '1'}
print(set_71 | set_70)  # 并集

"""
8. 差集
1. set.difference(set) 返回集合的差集。
2. set1 - set2 返回集合的差集。
3. set.difference_update(set) 集合的差集，直接在原来的集合中移除元素，没有返回值。
"""
set_80 = set('abcd12')
set_81 = set('12xyz')

print(set_80 - set_81)  # {'d', 'a', 'b', 'c'}
print(set_81 - set_80)  # {'y', 'x', 'z'}

"""
9.异或
1. set.symmetric_difference(set) 返回集合的异或。
2. set1 ^ set2 返回集合的异或。
3. set.symmetric_difference_update(set) 移除当前集合中在另外一个指定集合相同的元素，并将另外一个指定
集合中不同的元素插入到当前集合中。
"""
set_90 = set('1234')
set_91 = set('3xyz')

print(set_90.symmetric_difference(set_91))
print(set_90 ^ set_91)
# {'y', '2', '4', '1', 'z', 'x'}


"""
10. 包含关系判读
1. set.issubset(set) 判断集合是不是被其他集合包含，如果是则返回 True，否则返回 False。
2. set1 <= set2 判断集合是不是被其他集合包含，如果是则返回 True，否则返回 False。

1. set.issuperset(set) 用于判断集合是不是包含其他集合，如果是则返回 True，否则返回 False。
2. set1 >= set2 判断集合是不是包含其他集合，如果是则返回 True，否则返回 False。


"""
set_100 = set('1234')
set_101 = set('12')

print(set_100 >= set_101)  # True
print(set_101 >= set_100)  # False

"""
 11. isdisjoint 不相交
 set.isdisjoint(set) 用于判断两个集合是不是不相交，如果是返回 True，否则返回 False。
"""
set_110 = set('1234')
set_111 = set('12')
set_112 = set('34')

print(set_111.isdisjoint(set_110))  # False
print(set_110.isdisjoint(set_111))  # False
print(set_111.isdisjoint(set_112))  # True

# @.集合的转换
set_convert = set(range(10, 20, 2))
set_2_list = list(set_convert)
set_2_tuple = tuple(set_convert)
list_2_tuple = tuple(set_2_list)
print('set_convert', set_convert)  # {10, 12, 14, 16, 18}
print('set_2_list', set_2_list)  # [10, 12, 14, 16, 18]
print('set_2_tuple', set_2_tuple)  # (10, 12, 14, 16, 18)
print('list_2_tuple', list_2_tuple)  # (10, 12, 14, 16, 18)

# @.不可变集合

# Python 提供了不能改变元素的集合的实现版本，即不能增加或删除元素，类型名叫 frozenset 。需要注意的
# 是 frozenset 仍然可以进行集合操作，只是不能用带有 update 的方法。
# 1. frozenset([iterable]) 返回一个冻结的集合，冻结后集合不能再添加或删除任何元素。

frozen_set = frozenset(range(0, 100, 20))
print(frozen_set)

print('=========练习============')
index = 0
# 1. 怎么表示只包含⼀个数字1的元组。
index += 1
print(index, {1}, type((1,)))
# 2. 创建一个空集合，增加 {‘x’,‘y’,‘z’} 三个元素。
set_2 = set()
set_2.add('x')
set_2.add('y')
set_2.add('z')
index += 1
print(index, set_2)

# 3. 列表['A', 'B', 'A', 'B']去重。
lst = ['A', 'B', 'A', 'B']
index += 1
print(index, list(set(lst)))

# 4. 求两个集合{6, 7, 8}，{7, 8, 9}中不重复的元素
index += 1
print(index, {6, 7, 8} ^ {7, 8, 9})

# 差集指的是两个集合交集外的部分。
# 5. 求{'A', 'B', 'C'}中元素在 {'B', 'C', 'D'}中出现的次数。
index += 1
print(index, len({'B', 'C', 'D'} & {'A', 'B', 'C'}))
